/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package beans;

import entities.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import javax.ejb.LocalBean;
import javax.jms.*;

/**
 *
 * @author ryuju
 */
@Singleton
@LocalBean
public class SubmissionManager {
    @EJB
    private AssignmentManager assignmentManager;
    
    @Resource(mappedName = "jms/TestUnitMsgQueue")
    private Queue testUnitMsgQueue;
    @Resource(mappedName = "jms/TestUnitMsgQueueFactory")
    private ConnectionFactory testUnitMsgQueueFactory;
    
    @EJB
    private SubmissionFacade submissionFacade;
    
    
    
    HashMap<Long, Submission> submittedList;
    
    @PostConstruct
    void Init()
    {
        submittedList = new HashMap<Long, Submission>();
    }
    
    
    public boolean submit(Submission sub) {
        if(null == sub)
            return false;
        
        
        // make TestItem
        TestItem testItem = new TestItem();
        try {
            
            // get assignment
            Assignment asmt = assignmentManager.getAssignment(sub.getAssignmentID());
            if (null != asmt) {
                // set test unit property
                testItem.setSourceCode(sub.getSourceCode().getSrcCode());
                testItem.setSourceLang(sub.getSourceLanguage());
                testItem.setSubmitID(sub.getId());
                testItem.setTestInputs(asmt.getTestInputs());
                testItem.setTestOutputs(asmt.getTestOutputs());
                testItem.setTestPoints(asmt.getTestPoints());
                
                
                
                // send TestUnitMsg queue
                sendJMSMessageToTestUnitMsgQueue(testItem);
                Logger.getLogger(SubmissionManager.class.getName()).log(Level.INFO, "[SUBMIT] send test item into test queue ID: " + sub.getId());

            } else {
                Logger.getLogger(SubmissionManager.class.getName()).log(Level.INFO, "[SUBMIT] can not find assignment ID: " + sub.getAssignmentID());
                return false;
            }
        } catch (JMSException ex) {
            Logger.getLogger(SubmissionManager.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
        
        // not store source code.. (currently not use source code any more)
        sub.setSourceCode(new SourceCode("Submiited.."));
        
        // set submission status
        Date submitDate = new Date(System.currentTimeMillis());
        sub.setSubmitDate(submitDate);
        sub.setStatus("pending");
        submittedList.put(sub.getId(), sub);
        submissionFacade.create(sub);
        
        return true;
    }
    
    // if submission for submitID exists in the submittedList then remove from the submittedList and return submission
    // else return null
    public Submission getSubmittedItem(Long submitID) {
        Submission ret = null;
        if (submittedList.containsKey(submitID)) 
        {
            ret = submittedList.get(submitID);
            submittedList.remove(submitID);
        }
        return ret;
    }
    
    public void judge(Submission sub, TestResult testResult) {
        try {
            
            sub.setTestResultMsgs(testResult.getTestResultMsgs());
            
            List<Boolean> resultList = testResult.getTestResults();
            List<String> resultMsgList = testResult.getTestResultMsgs();
            
            sub.setTestResultMsgs(resultMsgList);
            sub.setTestResults(resultList);
            
            if(testResult.isExecuted())
            {
                boolean isPass = true;
                for(Boolean res : resultList)
                {
                    if(res.booleanValue() == false)
                    {
                        isPass = false;
                        break;
                    }
                }
                
                if(isPass)
                {
                    sub.setStatus("PASS");
                }
                else
                {
                    sub.setStatus("FAIL");
                }
                
            }
            else
            {
                sub.setStatus("Execution Fail[complie error or runtime error]");
            }
            
            
        } catch (Exception e) {
            Logger.getLogger(SubmissionManager.class.getName()).log(Level.SEVERE, null, e);
            sub.setStatus("Judge Fail.");
        }
        finally
        {
            submissionFacade.edit(sub);
        }
    }
    
    public boolean rejudge(Long asmtID) {
        // get submissions by assignment id
        // change status rejudge
        // submit 
        List<Submission> submitList = getSubmissionsByAssignmentID(asmtID);
        boolean ret = true;
        for(Submission sub : submitList)
        {
            sub.setStatus("rejudge");
            submissionFacade.edit(sub);
            
            ret = ret && submit(sub);
        }
        return ret;
    }
    
    public List<Submission> getAllSubmissions() {
        return submissionFacade.findAll();
    }
    
    public List<Submission> getSubmissionsByAssignmentID(Long asmtID) {
        return submissionFacade.findByAssignment(asmtID);
    }
    
    public List<Submission> getSubmissionsByUserLoginName(String name) {
        return submissionFacade.findByUserLoginName(name);
    }

    private Message createJMSMessageForjmsTestUnitMsgQueue(Session session, TestItem messageData) throws JMSException {
        // TODO create and populate message to send
        ObjectMessage om = session.createObjectMessage();
        om.setObject(messageData);
        return om;
    }

    private void sendJMSMessageToTestUnitMsgQueue(TestItem messageData) throws JMSException {
        Connection connection = null;
        Session session = null;
        try {
            connection = testUnitMsgQueueFactory.createConnection();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer messageProducer = session.createProducer(testUnitMsgQueue);
            messageProducer.send(createJMSMessageForjmsTestUnitMsgQueue(session, messageData));
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
                }
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
    
}
